export interface ReducerFunc{
    (prevState:any,args:any):stateType
}
export type stateType = Object & {
    [key:string]:any;
    [key:number]:any;
}
export interface actionTypes{
    type:string;
    [key:string]:any;
}
export interface EventFunc{
    (prevState:any,NewState:any,...args:any[]):void;
    (prevState:any,NewState:any,actionTypes:actionTypes):void;
    $TOKEN?:number;
    unsubscribe?:()=>void;
}
export interface EventMap{
    [token:number]:EventFunc
}
export class Event{
    private evtMap:EventMap = {}
    public token = -1;
    public subscribe(callback:EventFunc){
        const $TOKEN = this.token++;
        callback.$TOKEN = $TOKEN
        callback.unsubscribe = ()=>{
            this.unsubscribe($TOKEN)
        }
        return this.evtMap[$TOKEN] = callback
    }
    public unsubscribe(token:number){
        delete this.evtMap[token];
        return this
    }

    // 可复用的重载接口
    public async run(obj:any,NewState:any,...args:any[]):Promise<true>;
    public async run(obj:any,NewState:any,actionTypes:actionTypes){
        let key:string = ""
        try{
            for (key in this.evtMap) {
                await this.evtMap[key].bind(obj)(NewState,actionTypes)
            }
            return true
        }catch(e){
            throw Error(`事件错误:${e},TOKEN:${key}`)
        }
    }
}

export abstract class DataBase{
    protected state:stateType;
    public evt:Event = new Event();
    public abstract _name:string;
    public _parent?:DataBase;
    [ActionName:string]:ReducerFunc | Promise<ReducerFunc> | any

    public constructor(state?:stateType){
        this.state = state || {};
    }
    public subscribe(callback:EventFunc){
        return this.evt.subscribe(
            callback.bind(this)
        )
    }
    public unsubscribe(tokenOrCallback:number|EventFunc){
        if (typeof tokenOrCallback === "number"){
            return this.evt.unsubscribe(tokenOrCallback)
        }else{
            // if (tokenOrCallback.$TOKEN){ //不进行判断，仅靠规范
            return this.evt.unsubscribe(tokenOrCallback.$TOKEN as number)
            // }
            // return this.evt
        }
    }

    public getState(){ return this.state }

    // 可复用的重载接口
    
    public async dispatch(this:DataBase,...argv:any[]):Promise<stateType>; 
    public async dispatch(this:DataBase,actionTypes:actionTypes):Promise<stateType>{
        //===============Middleware==========
        MiddleWare.list.forEach((value:Function)=>{
            value.apply(this)
        });

        //================异步/同步Action================
        let NewState:stateType
        try{
            NewState = await this[actionTypes.type](actionTypes) 
        }catch(e){
            return Error("Active Action Error:"+e)
        }
        let obj:DataBase = this
        
        //===============父子事件====================
        try{
            let res = await obj.evt.run(obj,NewState,actionTypes);//接口，允许侵入性修改
            // if (res != true){   console.warn("Unexcepted Event")    }
            while(obj._parent !== undefined){
                obj = obj._parent
                res = await obj.evt.run(obj,NewState,actionTypes);//接口，允许侵入性修改
                // if (res != true){   console.warn("Unexcepted Event")    }
            }
        }catch(e){
            return Error(`${e},Active OBJ:${obj._name}`)
        }
        //==================成功返回值========================
        return (this.state = NewState)
    }

    //=====================父子关系的实现==================
    protected attach(parentClass:DataBase){
        this._parent = parentClass
        Object.defineProperty(
            this._parent.state,this._name,{
                get:()=>{
                    return this.state
                },
                configurable:true,
                enumerable:true
                // ,set:function(value:stateType){
                //     return modelIns.state = value
                // }
            }
        );
    }

    // 手动释放内存,删除父子联系
    public Unlink(){
        if (this._parent !== undefined){
            delete this._parent.state[this._name]
        }
    }
}

export namespace MiddleWare{
    export let list:Function[] = []
    export function add(func:Function){
        list.push(func)
    }
}